import { _decorator, Component, EventHandler, NodeEventType } from 'cc';
import { ToggleRedefine } from './ToggleRedefine';
const { ccclass, property, menu, executeInEditMode, executionOrder } = _decorator;

@ccclass('ToggleContainerRedefine')
@menu('myComponent/ToggleContainerRedefine')
@executionOrder(110)
@executeInEditMode
export class ToggleContainerRedefine extends Component {
  @property({ serializable: true })
  protected _allowSwitchOff = false;
  /**
   * @en
   * If this setting is true, a toggle could be switched off and on when pressed.
   * If it is false, it will make sure there is always only one toggle could be switched on
   * and the already switched on toggle can't be switched off.
   *
   * @zh
   * 如果这个设置为 true，那么 toggle 按钮在被点击的时候可以反复地被选中和未选中。
   */
  @property({
    tooltip: '如果这个设置为true，那么 toggle按钮在被点击的时候可以反复地披选中和未选中。',
  })
  get allowSwitchOff(): boolean {
    return this._allowSwitchOff;
  }

  set allowSwitchOff(value) {
    this._allowSwitchOff = value;
  }

  /**
   * @en
   * If Toggle is clicked, it will trigger event's handler.
   *
   * @zh
   * Toggle 按钮的点击事件列表。
   */
  @property({
    type: [EventHandler],
    tooltip: 'Toggle按钮的点击事件列表',
    serializable: true,
  })
  public checkEvents: EventHandler[] = [];

  /**
   * @en
   * Read only property, return the toggle items array reference managed by ToggleContainer.
   *
   * @zh
   * 只读属性，返回 toggleContainer 管理的 toggle 数组引用。
   */
  get toggleItems(): ToggleRedefine[] {
    return this.node.children
      .map((item) => {
        const toggle = item.getComponent('ToggleRedefine') as ToggleRedefine;
        if (toggle && toggle.enabled) {
          return toggle;
        }
        return null;
      })
      .filter(Boolean) as ToggleRedefine[];
  }

  public onEnable(): void {
    this.ensureValidState();
    this.node.on(NodeEventType.CHILD_ADDED, this.ensureValidState, this);
    this.node.on(NodeEventType.CHILD_REMOVED, this.ensureValidState, this);
  }

  public onDisable(): void {
    this.node.off(NodeEventType.CHILD_ADDED, this.ensureValidState, this);
    this.node.off(NodeEventType.CHILD_REMOVED, this.ensureValidState, this);
  }

  public activeToggles(): ToggleRedefine[] {
    return this.toggleItems.filter((x) => x.isChecked);
  }

  public anyTogglesChecked(): boolean {
    return !!this.toggleItems.find((x) => x.isChecked);
  }

  public notifyToggleCheck(toggle: ToggleRedefine): void {
    if (!this.enabledInHierarchy) {
      return;
    }

    for (let i = 0; i < this.toggleItems.length; i++) {
      const item = this.toggleItems[i]!;
      if (item === toggle) {
        continue;
      }
      item.isChecked = false;
    }

    if (this.checkEvents) {
      EventHandler.emitEvents(this.checkEvents, toggle);
    }
  }

  /**
   * @en Ensure toggles state valid.
   * @zh 确保 toggles 状态有效。
   */
  public ensureValidState(): void {
    const toggles = this.toggleItems;
    if (!this._allowSwitchOff && !this.anyTogglesChecked() && toggles.length !== 0) {
      const toggle = toggles[0]!;
      toggle.isChecked = true;
      this.notifyToggleCheck(toggle);
    }

    const activeToggles = this.activeToggles();
    if (activeToggles.length > 1) {
      const firstToggle = activeToggles[0];
      for (let i = 0; i < activeToggles.length; ++i) {
        const toggle = activeToggles[i];
        if (toggle === firstToggle) {
          continue;
        }
        toggle.isChecked = false;
      }
    }
  }
}
